home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir30
/
eerems11.zip
/
EER_UTIL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-23
|
9KB
|
272 lines
/* ***************************************************************
An AutoCAD ADS program to remove "extra entities"
This module contains utility functions (mostly used by eer_core.c)
Jon Fleming CIS 70334,2443 July 19, 1994
Public Domain; Please give me credit if you use this or any
significant portion of it
Revision history:
July 19, 1994 Version 1.0: Initial release
October 23, 1994 Version 1.1: Modified EER_CORE.C to handle negative line
endpoints properly, and to avoid checking for entities to remove when
no entities were selected in the "candidates for removal" selection set.
Modified EER_CORE.C and EEREM.H to include version number report when
DoEntityRemoval starts.
*********************************************************** */
#include <math.h>
#include <string.h>
#include <time.h>
#include "adslib.h"
#include "eerem.h"
/* Function prototypes */
short ColorStrToNum (char *);
ads_real DistancePointToLine(ads_point, ads_point, ads_point);
ads_real TransformAngle(ads_real, ads_point, ads_point);
int AngleIsBetween (ads_real, ads_real, ads_real);
VertexData GetVertexData(ads_name);
void SecToHMS (float, long *, long *, float *);
/* The constant 2*pi */
extern ads_real TwoPi;
/* Function to calculate the distance from a point to a line, equivalent
to the AutoCAD DISTANCE command snapping to the point and then
perpendicular to the line.
P1 is one point on the line.
P2 is another point on the line. It is the responsibility of the
calling routine to ensure that P2 is not equal to P1.
P3 is the point from which the distance is to be measured.
Return value: the distance in an ADS_REAL, positive if the point on the
line closest to P3 is between points P1 and P2, negative if the point
on the line closest to P3 is outside the line from P1 to P2.
*/
ads_real DistancePointToLine(ads_point P1, ads_point P2, ads_point P3) {
ads_real T4, X4, Y4, Z4;
/* Consider writing the equation of the line in terms of a parameter
T (which ranges from minus infinity to plus infinity). Say point
P1 corresponds to T=0 and point P2 corresponds to T=1, writing
the expression for the distance from P3 to any point on the line, then
differentiating with respect to T, and setting the result equal to zero
yields the following expression for the parameter T at the point
P4 where the distance to P3 is minimum:
*/
T4 = ((P2[X]-P1[X])*(P3[X]-P1[X]) + (P2[Y]-P1[Y])*(P3[Y]-P1[Y]) +
(P2[Z]-P1[Z])*(P3[Z]-P1[Z])) / ((P2[X]-P1[X])*(P2[X]-P1[X]) +
(P2[Y]-P1[Y])*(P2[Y]-P1[Y]) + (P2[Z]-P1[Z])*(P2[Z]-P1[Z]));
/* And the X, Y, Z coordinates of that point are: */
X4 = P1[X] + (P2[X]-P1[X])*T4;
Y4 = P1[Y] + (P2[Y]-P1[Y])*T4;
Z4 = P1[Z] + (P2[Z]-P1[Z])*T4;
/* So the distance is: */
if ((T4 <= 1.0) && (T4 >= 0.0)) {
return(sqrt((P3[X]-X4)*(P3[X]-X4) + (P3[Y]-Y4)*(P3[Y]-Y4) +
(P3[Z]-Z4)*(P3[Z]-Z4)));
}
else {
return(-sqrt((P3[X]-X4)*(P3[X]-X4) + (P3[Y]-Y4)*(P3[Y]-Y4) +
(P3[Z]-Z4)*(P3[Z]-Z4)));
}
}
/* Function to convert a string color number or name (from the system
variable CECOLOR) to an integer color number (suitable for an
Entity Association List).
Returns the integer color number.
*/
short ColorStrToNum (char *ColorString) {
char ColorNames[] = "BYBLOCKRED YELLOW GREEN CYAN BLUE MAGENTAWHITE";
char *Found;
/* If the color string is a color name ... */
if ((Found = strstr(ColorNames, strupr(ColorString))) != NULL) {
return ((Found - &ColorNames[0])/(7*sizeof(char)));
}
/* Check for BYLAYER. Note that the input string has already
been converted to uppercase */
if (strcmp(ColorString, "BYLAYER") == 0) {
return 256;
}
/* Otherwise, it must be a string version of the integer color number */
return(atoi(ColorString));
}
/* Function to convert an number of seconds to hours, minutes, and
seconds. */
void SecToHMS (float TotalSeconds, long *ElapsedHours, long *ElapsedMinutes,
float *ElapsedSeconds) {
float TempReal;
*ElapsedHours = floor(TotalSeconds/3600.0);
TempReal = TotalSeconds - ((float)*ElapsedHours)*3600.0;
*ElapsedMinutes = floor(TempReal/60.0);
*ElapsedSeconds = TempReal - ((float)*ElapsedMinutes)*60.0;
}
/* Function to return TRUE if it's first argument is an angle between
the angle defined by its second argument and the angle dfined by
its third argument. All angles must be from 0 to 2*pi. */
int AngleIsBetween(ads_real Angle, ads_real StartAngle, ads_real EndAngle) {
/* Check if the range between the start and end angle crosses zero */
if (StartAngle <= EndAngle) {
/* It doesn't cross zero, the test is straightforward */
if ((Angle >= StartAngle) && (Angle <= EndAngle)) {
return(TRUE);
}
else {
return(FALSE);
}
}
/* Zero is between the start and end, it's a little tricker */
else {
if ((Angle >= StartAngle) || (Angle <= EndAngle)) {
return(TRUE);
}
else {
return(FALSE);
}
}
}
/* I can't figure out the rules by which AutoCAD transforms angles from
one coordinate system to another, so here's a function that lets AutoCAD
do the work. The first argument is the angle, the second is the Z
axis of the "from" coordinate system, the third is the Z axis of the
"to" corrdinate system */
ads_real TransformAngle(ads_real Angle, ads_point From, ads_point To) {
ads_point OldVector, NewVector;
struct resbuf FromResBuf, ToResBuf;
ads_real NewAngle;
/* Form a unit vector in the XY plane of the "from" system, at the
correct angle from the X axis */
OldVector[0] = cos(Angle);
OldVector[1] = sin(Angle);
OldVector[2] = 0.0;
/* Have AutoCAD transform that into the "to" system */
FromResBuf.restype = RT3DPOINT;
FromResBuf.resval.rpoint[0] = From[0];
FromResBuf.resval.rpoint[1] = From[1];
FromResBuf.resval.rpoint[2] = From[2];
ToResBuf.restype = RT3DPOINT;
ToResBuf.resval.rpoint[0] = To[0];
ToResBuf.resval.rpoint[1] = To[1];
ToResBuf.resval.rpoint[2] = To[2];
ads_trans(OldVector, &FromResBuf, &ToResBuf, 0, NewVector);
/* And get the angle of that vector in the "to" coordinate system */
if ((NewAngle = atan2(NewVector[1], NewVector[0])) < 0.0) {
return(NewAngle + TwoPi);
}
else {
return(NewAngle);
}
}
/* Function to obtain data for a polyline vertex */
VertexData GetVertexData(ads_name VertexName) {
struct resbuf *VertexEAL, *VertexEALItem;
VertexData EntityVertexData;
/* Get a pointer to the start of the EAL */
VertexEAL = VertexEALItem = ads_entget(VertexName);
/* Set up default values for this vertex */
EntityVertexData.StartWidth = EntityVertexData.EndWidth = EntityVertexData.Bulge = 0.0;
EntityVertexData.Flags = 0;
EntityVertexData.Location[0] = EntityVertexData.Tangent[0] = 0.0;
EntityVertexData.Location[1] = EntityVertexData.Tangent[1] = 0.0;
EntityVertexData.Location[2] = EntityVertexData.Tangent[2] = 0.0;
/* Get the values for this vertex */
while (VertexEALItem != NULL) {
switch (VertexEALItem->restype) {
case 0: {
strcpy(EntityVertexData.Type, VertexEALItem->resval.rstring);
break;
}
case 10: {
ads_point_set(VertexEALItem->resval.rpoint, EntityVertexData.Location);
break;
}
case 40: {
EntityVertexData.StartWidth = VertexEALItem->resval.rreal;
break;
}
case 41: {
EntityVertexData.EndWidth = VertexEALItem->resval.rreal;
break;
}
case 42: {
EntityVertexData.Bulge = VertexEALItem->resval.rreal;
break;
}
case 50: {
ads_point_set(VertexEALItem->resval.rpoint, EntityVertexData.Tangent);
break;
}
case 70: {
EntityVertexData.Flags = VertexEALItem->resval.rint;
break;
}
}
VertexEALItem = VertexEALItem->rbnext;
}
ads_relrb(VertexEAL);
return (EntityVertexData);
}